
from user_agent import generate_user_agent
from secrets import token_hex
from eth_account import Account
from string import ascii_lowercase, digits
from random import choice
from requests import request
from time import sleep

from config import (
    SECMAIL_DOMAINS,
    WAIT_MAIL_ROUNDS,
    WAIT_MAIL_TIME,
    PROXY_TYPE,
    CHANGE_PROXY_URL,
    PROXY_URL,
    ALLOWED_PROXY_SCHEMES,
    TOR_PORT,
    PROXY_URL_LIST,
    EXIT_IF_PROXY_LISt_IS_OVER,
)
from log import logger


def proxy_url_to_proxies(url):
    schema, username, password, host, port = ['']*5
    try:
        schema, url = url.split('://')
        if '@' in url:
            auth, url = url.split('@')
            username, password = auth.split(':')
        host, port = url.split(':')
    except Exception as e:
        logger.error(f'Zjef5mTM4J3NWmHP; invalid proxy format: {url}')
        return {'status': 'error'}

    if not schema in ALLOWED_PROXY_SCHEMES:
        logger.error(f'2Hsm4eUf3YjktahK; {schema}')

    return {
        'status': 'success',
        'data': {
            'proxies': {
                'http': f'{schema}://{username}:{password}@{host}:{port}',
                'https': f'{schema}://{username}:{password}@{host}:{port}',
            }
        }
    }


def proxy_validation(proxies):
    response = request('GET', 'http://myexternalip.com/raw', proxies=proxies)
    if response.status_code != 200:
        logger.error(f'code: kvbMTudHNS8nkt8d; {response.status_code} {response.text}')
        return {'status': 'error'}
    if not response.text:
        logger.error(f'code: CBTc5NEGE75vuwCU; {response.status_code} {response.text}')
        return {'status': 'error'}
    return {
        'status': 'success',
        'data': {
            'external_ip': response.text
        }
    }

def change_proxy_with_url(url):
    sleep(30)
    response = request('GET', url)
    if not response.ok:
        logger.error(f'code: wzuz3FPKaJmJtEJb; {response.status_code} {response.text}')
        return {'status': 'error'}
    logger.debug(response.text)

    return {'status': 'success'}


def parse_1secmail_mail(email, _from, subject, proxies, without_mail_id=None):

    mail_id = None

    split_email = email.split('@')
    url = f'https://www.1secmail.com/api/v1/?action=getMessages&login={split_email[0]}&domain={split_email[1]}'
    
    all_break = False
    for _ in range(WAIT_MAIL_ROUNDS):

        if all_break == True: break

        response = request('GET', url, proxies=proxies)
        if not response.status_code == 200:
            sleep(WAIT_MAIL_TIME)
            continue
        if not response.json():
            sleep(WAIT_MAIL_TIME)
            continue

        for mail in response.json():

            if all_break == True: break

            if not _from in mail['from'] or not subject in mail['subject']:
                logger.debug(f'unknown mail: {mail}')
                continue
            else:
                mail_id = mail['id']
                all_break = True

        sleep(WAIT_MAIL_TIME)

    if not mail_id:
        logger.error('code: wd75Kpbn,cannnot get mail')
        return {'status': 'error'}
    if mail_id == without_mail_id:
        logger.debug('repetition mail, start parser again')
        return parse_mail(email, _from, subject, without_mail_id, proxies)

    url = f'https://www.1secmail.com/api/v1/?action=readMessage&login={split_email[0]}&domain={split_email[1]}&id={mail_id}'

    response = request('GET', url)
    if not response.status_code == 200:
        logger.error(f'code: zK997XAv, {response.status_code} {response.text}')
        return {'status': 'error'}
    if not response.text or response.text == 'Message not found':
        logger.error(f'code: VaPXmY7f, {response.text}')
        return {'status': 'error'}

    return {
        'status': 'success',
        'data': {
            'id': mail_id,
            'text': response.text,
            'json': response.json()
        }
    }


def get_random_string(length=10):
    return ''.join([choice(ascii_lowercase+digits) for _ in range(length)])

def get_random_1secmail_email():
    return get_random_string() + '@' + choice(SECMAIL_DOMAINS)


def get_email():
    return get_random_1secmail_email()

def get_proxy(number):

    if PROXY_TYPE == 0:

        return {
            'type': 'none',
            'external_ip': '',
            'proxies': {
                'http': '',
                'https': '',
            },
        }

    elif PROXY_TYPE == 1:

        p = get_random_string()
        proxies = {
            'http': f'socks5://u:{p}@127.0.0.1:{TOR_PORT}',
            'https': f'socks5://u:{p}@127.0.0.1:{TOR_PORT}',
        }

        external_ip = request('GET', 'https://myexternalip.com/raw', proxies=proxies)
        if not external_ip.ok:
            assert False, 'code: Yn2dS3w7rTjbVEAK'
        if not external_ip.text:
            assert False, 'code: B3gzanfpjURj762r'

        return {
            'type': 'tor',
            'external_ip': external_ip.text,
            'proxies': proxies
        }

    elif PROXY_TYPE == 2:
        
        change_proxy_with_url_result = change_proxy_with_url(CHANGE_PROXY_URL)
        if change_proxy_with_url_result['status'] != 'success':
            assert False, ['dqcjheHVm75qk6fH', proxies]
        proxy_url = PROXY_URL
        _type = 'change'

    elif PROXY_TYPE == 3:
        
        if len(PROXY_URL_LIST) == number:
            if EXIT_IF_PROXY_LISt_IS_OVER:
                logger.info('Список прокси закончился, выхожу.')
                exit()
            else:
                l = number // len(PROXY_URL_LIST) * PROXY_URL_LIST
                proxy_url = PROXY_URL_LIST[number-l]
        else:
            proxy_url = PROXY_URL_LIST[number]

        _type = 'list'

    proxies = proxy_url_to_proxies(proxy_url)
    if proxies['status'] != 'success':
        assert False, ['xsnYjY6BwbLw8X9q', str(proxies)]
    proxy_validation_result = proxy_validation(proxies['data']['proxies'])
    if proxy_validation_result['status'] != 'success':
        assert False, ['Pk8sv9wHkCuPWNYv', proxy_validation_result]
    external_ip = proxy_validation_result['data']['external_ip']

    return {
        'type': _type,
        'external_ip': external_ip,
        'proxies': proxies['data']['proxies'],
    }

def get_user_agent():
    return generate_user_agent()

def get_wallet():

    priv = token_hex(32)
    private_key = "0x" + priv
    wallet = Account.from_key(private_key)

    return {
        'address': wallet.address,
        'private_key': wallet._private_key.hex(),
    }
